๐Ÿ“Š Comprehensive Indie Demo Indicator

Table of Contents

๐Ÿ“Š Comprehensive Indie Demo Indicator

Version: Indie v5 Language: Indie Chart Type: Non-overlay (separate pane) Purpose: Demonstrates multiple Indie language features including multi-timeframe analysis, dynamic markers, volatility alerts, and advanced plotting. Author: Pavel Medd


๐Ÿ” Overview

This indicator is designed as a rich, educational showcase of the Indie scripting language. It mimics the structure and behavior of popular indicators like MACD and RSI, while extending functionality to higher-timeframe context evaluation and volatility detection. Whether youโ€™re learning Indie or building complex custom indicators, this example includes advanced concepts like:


๐Ÿงฎ Indicator Logic

1. MACD-like Line

Calculates the difference between a fast EMA and a slow SMA on the current timeframe.

main_line = fast_ema - slow_sma
signal_line = EMA of main_line (smoothing factor 9)

2. Momentum Histogram

Plots the price difference between current and previous close with color indicating direction.

3. Volatility Columns

Based on ATR as a % of price. If volatility exceeds 5%, a red alert marker appears on the chart.

4. Cross-over Markers

Detects when price crosses the slow SMA:

5. Higher Timeframe Context

Uses a secondary context to compute RSI and SMA on a user-defined higher timeframe (e.g., 1D). If the price is above the higher-timeframe SMA, a green HTF marker with RSI value appears.


โš™๏ธ Inputs

Parameter Type Description
Fast Length int Period for fast EMA
Slow Length int Period for slow SMA
Volatility Multiplier float Scales height of volatility columns
Show Higher Timeframe bool Toggle visibility of HTF marker
Higher Timeframe TimeFrame Target timeframe for HTF analysis (e.g., โ€œ1Dโ€)

๐Ÿ“ˆ Outputs

Output Type Description
Main Line Line MACD-style line (EMA - SMA)
Signal Line Line EMA of Main Line
Momentum Histogram Price delta between candles
HTF Marker Marker RSI-based marker from higher timeframe
Crossover Marker Marker Shows BUY/SELL arrows
Volatility Alert Marker Appears if ATR > 5% of close
Volatility Columns Columns Visualizes ATR volatility scaled by multiplier

๐Ÿ“Œ Additional Notes

Indie Code

open source file


# indie:lang_version = 5
# Comprehensive Indie Demo Indicator
# This indicator demonstrates multiple Indie language features with full explanatory comments
# ยฉ 2025 Pavel Medd (@pavelmedd)
# Licensed under the MIT License. You may use, copy, modify, merge, publish, 
# distribute, sublicense, and/or sell copies of the Software, subject to the 
# conditions of the MIT license. Full license text: https://opensource.org/licenses/MIT

import math
from indie import indicator, param, plot, color, level, band, MutSeriesF, Optional, MainContext, sec_context, line_style, TimeFrame
from indie.algorithms import Sma, Ema, Rsi, Atr
from indie.plot import marker_style, marker_position, Line, Marker, Histogram, Columns

# Secondary context to compute values on a higher timeframe
@sec_context
def HigherTFContext(self):
    # 14-period RSI and 50-period SMA on the higher timeframe
    rsi = Rsi.new(self.close, 14)
    sma = Sma.new(self.close, 50)
    # If close is above the SMA, we consider it an uptrend (score 1.0), else 0.0
    trend_score = 1.0 if self.close[0] > sma[0] else 0.0
    return rsi[0], sma[0], trend_score

# Main indicator class
@indicator('Comprehensive Demo', overlay_main_pane=False)
@param.int('fast_length', default=12, min=1, max=50, title='Fast Length')  # Fast EMA length
@param.int('slow_length', default=26, min=1, max=100, title='Slow Length')  # Slow SMA length
@param.float('volatility_mult', default=2.0, min=0.5, max=5.0, title='Volatility Multiplier')  # Volatility scaling factor
@param.bool('show_higher_tf', default=True, title='Show Higher Timeframe')  # Toggle for showing higher timeframe marker
@param.time_frame('higher_tf', default='1D', title='Higher Timeframe')  # Timeframe for higher timeframe analysis
@plot.line(title='Main Line')  # Custom MACD-like line
@plot.line(title='Signal Line')  # EMA of the main line
@plot.histogram(title='Momentum')  # Difference between current and previous close
@plot.marker(title='HTF Marker')  # Marker indicating higher timeframe trend
@plot.marker(title='Crossover Marker')  # Buy/Sell crossover signal marker
@plot.marker(title='Volatility Alert')  # Alert marker for high volatility
@plot.columns(title='Volatility')  # Column plot for ATR-based volatility
class Main(MainContext):

    def __init__(self, higher_tf: TimeFrame):
        # Default values for higher timeframe fallback
        self.htf_rsi_val = 50.0
        self.htf_sma_val = 0.0
        self.htf_trend_val = 0.0

        # Optional values for dynamic higher timeframe marker
        self._htf_marker_value = Optional[float](None)
        self._htf_marker_color = color.GRAY
        self._htf_marker_text = Optional[str](None)

        # Use higher timeframe only if different from current
        if higher_tf != self.time_frame:
            rsi_val, sma_val, trend_score = self.calc_on(HigherTFContext, time_frame=higher_tf)
            self.htf_rsi_val = float(rsi_val[0])
            self.htf_sma_val = float(sma_val[0])
            self.htf_trend_val = float(trend_score[0])

    def calc(self, fast_length, slow_length, volatility_mult, show_higher_tf, higher_tf):
        # Calculate fast and slow moving averages
        fast_ma = Ema.new(self.close, fast_length)
        slow_ma = Sma.new(self.close, slow_length)
        rsi = Rsi.new(self.close, 14)

        # Crossover detection: bullish (cross up) or bearish (cross down)
        cross_up = self.close[1] <= slow_ma[1] and self.close[0] > slow_ma[0]
        cross_down = self.close[1] >= slow_ma[1] and self.close[0] < slow_ma[0]

        crossover_val = math.nan
        crossover_text: Optional[str] = Optional[str](None)
        crossover_color = color.GRAY

        crossover_detected = cross_up or cross_down
        if crossover_detected:
            crossover_val = 80.0 if cross_up else 20.0
            direction = "+" if cross_up else "-"
            arrow = "^" if cross_up else "v"
            label = "BUY" if cross_up else "SELL"
            crossover_color = color.LIME if cross_up else color.RED
            crossover_text = Optional[str](arrow + " " + label + " " + direction)

        # Momentum calculation: price difference between current and previous close
        momentum_value = self.close[0] - self.close[1]
        momentum_color = color.GREEN if momentum_value > 0 else color.RED

        # ATR-based volatility: normalized as percentage of current close
        atr = Atr.new(10)
        volatility = atr[0] / self.close[0] * 100

        # High volatility marker: appears on the price chart if volatility > 5%
        vol_marker = Marker(math.nan)
        if volatility > 5.0:
            vol_marker = Marker(
                self.close[0],
                text="X High Vol!",
                color=color.RED
            )

        # MACD-like line: difference between fast and slow MA
        main_line = fast_ma[0] - slow_ma[0]
        signal_series = MutSeriesF.new(main_line)
        signal_line = Ema.new(signal_series, 9)[0]

        # Convert stored values to series for plotting HTF markers
        htf_rsi = MutSeriesF.new(self.htf_rsi_val)
        htf_trend = MutSeriesF.new(self.htf_trend_val)

        # HTF marker update every 50 bars to reduce clutter
        if show_higher_tf and self.bar_index % 50 == 0:
            marker_val = 80.0 if htf_trend[0] > 0 else 20.0
            self._htf_marker_value = Optional[float](marker_val)
            self._htf_marker_color = color.GREEN if htf_trend[0] > 0 else color.RED
            rsi_val = htf_rsi[0]
            rsi_str = "HTF RSI: " + str(int(round(rsi_val))) if not math.isnan(rsi_val) else "x"
            self._htf_marker_text = Optional[str](rsi_str)
        else:
            self._htf_marker_value = Optional[float](None)
            self._htf_marker_text = Optional[str](None)

        htf_marker_val = self._htf_marker_value.value_or(math.nan)
        htf_marker_text = self._htf_marker_text.value_or("") if self._htf_marker_text is not None else None

        # Final output: all elements to render on chart
        return (
            Line(main_line),  # MACD-like signal
            Line(signal_line),  # Smoothed signal line
            Histogram(momentum_value, color=momentum_color),  # Price momentum
            Marker(htf_marker_val, text=htf_marker_text, color=self._htf_marker_color)
                if show_higher_tf and not math.isnan(htf_marker_val) else Marker(math.nan),
            Marker(crossover_val, text=crossover_text.value_or("") if crossover_text is not None else None, color=crossover_color)
                if crossover_detected else Marker(math.nan),
            vol_marker,  # Volatility alert
            Columns(
                volatility * volatility_mult,  # Volatility column
                color=color.rgba(
                    255 if volatility > 2 else 100,
                    100,
                    255 if volatility <= 2 else 100,
                    0.5
                )
            )
        )